#include "threadmount.h"

threadmount::threadmount()
{
    port = NULL;
    bStop = true;
    int status = WARNING;
    pLog = logmanager::getInstance("");
    pLog->AddMessage(INFO, id_Mount + OK, __LINE__, __FILE__,
                        QObject::tr("Load ThreadMount"));
    emit PeriphError(MONT,status);
    pMount = new gto1200();
    pMount->bSimu = false;
}

void threadmount::setMode(int val)
{
    Mode = val;
}


threadmount::~threadmount()
{
    if (pMount)
        delete pMount;
    pLog->AddMessage(INFO, id_Mount + OK, __LINE__, __FILE__,
                        QObject::tr("Unload ThreadMount"));
}

void threadmount::run()
{
    int status = SUCCESS;
    status = SearchMount();
    if (status == SUCCESS)
    {
        setMode(LIVE);
        pMount->SetGuideRate(1);
        pMount->SetSlewSpeed(1200);
        pMount->SetSlewRate(1200);
    } else
    {
        setMode(SEARCH);
    }
   do {
        switch (Mode)
        {
            case SEARCH :
                msleep(1500);
                status = SearchMount();
                if (status == SUCCESS){setMode(LIVE);}
                emit PeriphError(MONT,status);
                break;

            case LIVE :
                ReadInfos();
                break;
        }
        msleep(60);
    } while (bStop == true);
}


/**
 * @brief
 *
 * @return QVector<QextSerialPort *>
 */
QVector<QextSerialPort*> threadmount::ScanSerialPort()
{
    QString PortName ;
    QString label;
    PortName = "COM1";
    QVector<QextSerialPort*> TabValidePort;
    #ifdef __linux__
        PortName = "/dev/ttyUSB0";
        stringOS = "RASPBERRY LINUX";
    #endif
    #ifdef _WIN32
        PortName = "COM4";
        stringOS = "DELL PC WINDOWS";
    #endif


    label.sprintf("========== SCANNING SERIAL DEVICE ==========");
    pLog->AddMessage(INFO, 1000 + OK, __LINE__, __FILE__,label);

    QList<QextPortInfo> ports = QextSerialEnumerator::getPorts();

    foreach (QextPortInfo info, ports) {
       label.sprintf("port name: %s",info.portName.toStdString().c_str());
       pLog->AddMessage(INFO, 1000 + OK, __LINE__, __FILE__,label);
       label.sprintf("port name: %s",info.friendName.toStdString().c_str());
       pLog->AddMessage(INFO, 1000 + OK, __LINE__, __FILE__,label);
       label.sprintf("port name: %s",info.physName.toStdString().c_str());
       pLog->AddMessage(INFO, 1000 + OK, __LINE__, __FILE__,label);
       label.sprintf("port name: %s",info.enumName.toStdString().c_str());
       pLog->AddMessage(INFO, 1000 + OK, __LINE__, __FILE__,label);
       label.sprintf("port name: %d",info.vendorID);
       pLog->AddMessage(INFO, 1000 + OK, __LINE__, __FILE__,label);
       label.sprintf("port name: %d",info.productID);
       label.sprintf("===================================");
       pLog->AddMessage(INFO, 1000 + OK, __LINE__, __FILE__,label);
    }
    msleep(20);
    bool EtatPort = false;
    pLog->AddMessage(INFO, 1000 + OK, __LINE__, __FILE__,"Searching serial port connected ...");

     // Boucle scan des ports
    for (int i = 0; i < ports.count(); i++)
    {
     if (!ports[i].portName.isEmpty())
     {
         //if (port != NULL){ port->close(); free(port);port = NULL;};
         port = new QextSerialPort(ports[i].portName);


         EtatPort =  port->open(QIODevice::ReadWrite | QIODevice::Unbuffered);
         if (EtatPort)
         {
             if ( ports[i].productID != 0)
             {
                 label = label.sprintf("Port %s device detected : %d",
                               ports[i].portName.toStdString().c_str(),
                               ports[i].productID);
                 pLog->AddMessage(SUCCESS, 1000 + OK, __LINE__, __FILE__,label);
                 TabValidePort  << port;
             } else
             {
                 label = label.sprintf("Port %s no device detected.",
                               ports[i].portName.toStdString().c_str());
                 pLog->AddMessage(WARNING, 1000 + OK, __LINE__, __FILE__,label);

             }
         } else
         {
             // No Device
             label = label.sprintf("Port %s inactif",
                           ports[i].portName.toStdString().c_str());
             pLog->AddMessage(CRITICAL, 1000 + OK, __LINE__, __FILE__,label);   
         }

     }
    }
    pLog->AddMessage(INFO, 1000 + OK, __LINE__, __FILE__,"===================================");
    label.sprintf("Result: %d port(s) detected with device connected",TabValidePort.count());
    pLog->AddMessage(INFO, 1000 + OK, __LINE__, __FILE__,label);
    pLog->AddMessage(INFO, 1000 + OK, __LINE__, __FILE__,"===================================");



    if (TabValidePort.count() > 0)
    {
        emit SendStatusSerial(tr("%n serial device(s) detected","",TabValidePort.count()),SUCCESS);
    }
    return TabValidePort;
}

int threadmount::OpenPort(QString PortNum)
{
    QString PortName = PortNum;
    pMount->port = new QextSerialPort(PortName, QextSerialPort::Polling);
    pMount->port->open(QIODevice::ReadWrite | QIODevice::Unbuffered);

    // configuration du port
    pMount->port->setBaudRate(BAUD9600);
    pMount->port->setFlowControl(FLOW_OFF);
    pMount->port->setParity(PAR_NONE);
    pMount->port->setDataBits(DATA_8);
    pMount->port->setStopBits(STOP_1);
    pMount->port->open(QIODevice::ReadWrite);
    pMount->port->setTimeout(1000);
    pMount->port->setDtr(true);
    pMount->port->setRts(true);
    pMount->port->flush();

    bool status1  = pMount->port->isOpen();
    QString PortName1 = pMount->port->portName();
    bool isread = pMount->port->isReadable();
   // qDebug() << "status port " << status1 << "  portname: " << PortName1.toStdString().c_str() << "  isread " << isread;
    return SUCCESS;



}

/**
 * @brief Scan all valide serial port\n
 * and search mount type;
 *
 * @param QString Mount type string
 * @param QVector<QextSerialPort *Port>
 * @return in   Status
 */
int threadmount::SearchMount(QVector<QextSerialPort *> TabPort,QString MountType)
{
    int status = SUCCESS;

    QString label;
    if (TabPort.count() == 0 ||  MountType.isEmpty())
    {
        // Error no valide serial port
        status = CRITICAL;
        pLog->AddMessage(status, 1000 + OK, __LINE__, __FILE__,"Search mount: no mount detected");
        emit SendStatusSerial(tr("No Mount detected"),status);
    } else
    {
         for (int i =0; i < TabPort.count(); i++ )
         {
             TabPort[i]->close();
            // ouverture du port
            OpenPort(TabPort[i]->portName());
            // lecture des informations sur le port
            QString version;
            this->pMount->sendMessage(":V#");
            this->pMount->readPort(&version);

            if (!version.compare("I#",Qt::CaseSensitive))
            {
                 label.sprintf("Monture Astrophysics detected. Version: %s",version.toStdString().c_str());
                 pLog->AddMessage(SUCCESS, 1000 + OK, __LINE__, __FILE__,label);
                 emit SendStatusSerial(tr("Mount astrophysics detected"),SUCCESS);
                 break;
            } else
            {
                pMount->port->close();
            }

         }
    }
    //pLog->AddMessage(INFO, 1000 + OK, __LINE__, __FILE__,"End Detection mount");
    return status;
}
/**
 * @brief Scan if mount is connected on port.\n
 *
 * @param QString Mount type string
 * @param QextSerialPort    port
 * @return in   Status
 */
int threadmount::SearchMount(QextSerialPort * port)
{
    int status = SUCCESS;
    port->setBaudRate(BAUD9600);
    port->setFlowControl(FLOW_OFF);
    port->setParity(PAR_NONE);
    port->setDataBits(DATA_8);
    port->setStopBits(STOP_1);
    port->setTimeout(1000);
    port->setDtr(true);
    port->setRts(true);
    port->flush();
    pMount->port = port;
    pMount->sendMessage(":V#");
    return status;
}


int threadmount::SearchMount()
 {
    int status = SUCCESS;
    TabValidePort = ScanSerialPort();
    status = SearchMount(TabValidePort, "gto1200");
    return status;
 }


int threadmount::ReadInfos()
{
    int Status = SUCCESS;
    QTime TimeUTC;

    if (pMount)
    {
        Status = pMount->GetRa(&pMount->SettingsMount.CurrentCoord);
        if (Status != SUCCESS)
            return Status;
        Status = pMount->GetDec(&pMount->SettingsMount.CurrentCoord);
        if (Status != SUCCESS)
            return Status;
        TimeStruct now;

        now.Year		= QDateTime::currentDateTime().toUTC().date().year();
        now.Month		= QDateTime::currentDateTime().toUTC().date().month();
        now.MonthDay	= QDateTime::currentDateTime().toUTC().date().day();

        TimeUTC = QDateTime::currentDateTime().toUTC().time();
        now.Hour		= TimeUTC.hour();
        now.Minute		= TimeUTC.minute();
        now.Second		= TimeUTC.second();
        now.Millisecond = TimeUTC.msec();

        // a voir: la monture renvoie le temps sideral mais c'est pas le meme que celui du calcul
        TimeStruct SideralTime_Mount;
        pMount->GetCurrentSideralTime(&SideralTime_Mount);
        // --------------------------------------------------------------------
        //pScience->GetSideralTime(pMount->SettingsMount.Localisation.coordinates,now,&pMount->SettingsMount.SideralTime);
        // ---------------------------------------------------------------------
        Status = pMount->GetLocalTime(&pMount->SettingsMount.LocalTime);
        if (Status != SUCCESS)
            return Status;
        //pScience->GetHourAngle(
        //	pMount->SettingsMount.SideralTime,
        //	pMount->SettingsMount.CurrentCoord,
        //	&pMount->SettingsMount.HourAngle);

        pMount->GetAltitude(&pMount->SettingsMount.Altitude);
        pMount->GetAzimuth(&pMount->SettingsMount.Azimuth);
        emit SendInfos(pMount->SettingsMount);
    }
    return Status;
}


/**
 * @brief Move North
 * signal from IMM
 */
void threadmount::MoveN()
{
    int val = 0;
    QFuture<void> taskNorth = QtConcurrent::run(this,
            &threadmount::ThreadMoveNorth, val);
    //pMount->ThreadMoveNorth(0);
}
/**
 * @brief Move Est
 * signal from IMM
 */
void threadmount::MoveE()
{
    int val = 0;
    QFuture<void> taskEst = QtConcurrent::run(this,
            &threadmount::ThreadMoveEast, val);
}
/**
 * @brief Move West
 * signal from IMM
 */
void threadmount::MoveW()
{
    int val = 0;
    QFuture<void> taskWest = QtConcurrent::run(this,
            &threadmount::ThreadMoveWest, val);

}
/**
 * @brief Move South
 * signal from IMM
 */
void threadmount::MoveS()
{
    int val = 0;
    QFuture<void> taskSouth = QtConcurrent::run(this,
            &threadmount::ThreadMoveSouth, val);
}
/**
 * @brief Stop Mount
 * signal from IMM
 */
void threadmount::Stop()
{
    QFuture<void> taskStop = QtConcurrent::run(this,
            &threadmount::ThreadMoveStop);
}


/**
 * @brief thread Move North
 * @details permet d'aller au nord sans bloquer l'IHM
 *
 * @param[in]	int	time ms
 */
void threadmount::ThreadMoveStop()
{
    pMount->Stop("All");
}


/**
 * @brief thread Move North
 * @details permet d'aller au nord sans bloquer l'IHM
 *
 * @param[in]	int	time ms
 */
void threadmount::ThreadMoveNorth(int val)
{
    pMount->MoveNorth(val);
}

/**
 * @brief thread Move South
 * @details permet d'aller au nord sans bloquer l'IHM
 *
 * @param[in]	int	time ms
 */
void threadmount::ThreadMoveSouth(int val)
{
    pMount->MoveSouth(val);
}

/**
 * @brief thread Move East
 * @details permet d'aller au est sans bloquer l'IHM
 *
 * @param[in]	int	time ms
 */
void threadmount::ThreadMoveEast(int val)
{
    pMount->MoveEast(val);
}

/**
 * @brief thread Move West
 * @details permet d'aller a l'ouest sans bloquer l'IHM
 *
 * @param[in]	int	time ms
 */
void threadmount::ThreadMoveWest(int val)
{
    pMount->MoveWest(val);
}




